<template>
  <div>
    <!-- ref -->
    ref：{{ user1 }}

    <hr />

    <!-- shallowRef -->
    shallowRef：{{ user2.name }}

    <button @click="changeUser2Name">更新 shallowRef 属性值（无效）</button>
    <button @click="changeShallowRef">整体更新 shallowRef 值（有效）</button>
    <button @click="handleTriggerRef">triggerRef强制更新ref</button>

    <hr />

    <!-- customRef -->
    customRef：{{ user3.name }}

    <button @click="handleTriggerCustomRef">更新 customRef 属性值</button>

    <hr />

    <!-- ref 获取 DOM 元素 -->
    <div ref="DivRef">我是 div</div>
  </div>
</template>

<script setup lang="ts">
import { ref, isRef, shallowRef, triggerRef, customRef } from "vue";

// 注：ref 和 shallowRef 修改值时不能写在一块，不然 shallowRef 的数据也会更新。
// 例子: user1.value = "李四"; user2.value.name = "赵六"; 整体数据都会更新（官方设计如此）。

// 【ref】 将数据变成响应式数据
const user1 = ref("张三");

// 【isRef】 检查是否是ref
console.log(isRef(user1));

// 【shallowRef】 浅层响应式（自身是响应式的，内部的数据不是响应式的）
const user2 = shallowRef({ name: "李四" });

const changeUser2Name = () => {
  user2.value.name = "王五";
};

const changeShallowRef = () => {
  user2.value = { name: "赵六" };
};

// 【triggerRef】 触发响应式（强制更新ref，shallowRef 也会被影响）
const handleTriggerRef = () => {
  user2.value.name = "刘七";
  triggerRef(user2);
};

// 【customRef】 自定义响应式
const myRef = <T>(value: T) => {
  let timer: null | number = null;

  return customRef((track, trigger) => ({
    get() {
      track(); // 收集依赖
      return value;
    },

    set(newVlaue) {
      clearInterval(timer as unknown as number);

      timer = setTimeout(() => {
        clearTimeout(timer as unknown as number);
        timer = null;
        value = newVlaue;
        trigger(); // 触发依赖更新
      }, 500);
    },
  }));
};

const user3 = myRef({ name: "王麻子" });

const handleTriggerCustomRef = () => {
  console.log(user3); // Ref<Object> 控制台 - 设置 - Console - Enable custom formatters

  // user3.value.name = "李八"; // 无效
  // triggerRef(user3); // 强制更新

  // ************************************

  user3.value = { name: "李八" }; // 有效
};

// 【ref 获取 DOM 元素】
const DivRef = ref<HTMLElement>();
setTimeout(() => {
  console.log(DivRef.value?.innerHTML);
}, 100);
</script>
